// GTY
/*FGameplayAbilityTargetData_LocationInfo
 *这个类用于表示基于位置的目标数据。例如，一个技能可能需要在某个特定的地点释放效果，而不是针对某个特定的角色。
 *FGameplayAbilityTargetData_LocationInfo 包含了这样的位置信息，如世界坐标或其他与位置相关的数据。

FGameplayAbilityTargetData_ActorArray
这个类用于表示基于一组角色的目标数据。如果一个技能需要影响多个角色，那么可以使用这个类。
它包含了一个角色数组（通常是 AActor 或其派生类的实例），这样技能就可以对数组中的每个角色应用效果。

FGameplayAbilityTargetData_SingleTargetHit
这个类用于表示单个角色作为目标的数据。当一个技能只影响一个角色时，可以使用这个类。
它通常包含了关于这个单一目标的信息，比如该角色的位置、健康状态或其他相关数据。
*/


#include "AbilitySystem/AbilityTask/TargetDataUnderMouse.h"

#include "AbilitySystemComponent.h"
#include "auragame/auragame.h"

UTargetDataUnderMouse* UTargetDataUnderMouse::CreateTargetDataUnderMouse(UGameplayAbility* OwningAbility)
{
	UTargetDataUnderMouse* MyObj = NewAbilityTask<UTargetDataUnderMouse>(OwningAbility);
	return MyObj;
}

void UTargetDataUnderMouse::Activate()
{
	//当前角色是否由本地玩家控制   如果是客户端控制器控制，实现将数据发射到服务器端
	const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled();
	if (bIsLocallyControlled)
	{
		SendMouseCursorData();
	}
	else
	{
		const FGameplayAbilitySpecHandle SpecHandle = GetAbilitySpecHandle();
		const FPredictionKey ActivationPredictionKey = GetActivationPredictionKey();
		AbilitySystemComponent.Get()->AbilityTargetDataSetDelegate(SpecHandle, ActivationPredictionKey).AddUObject(this, &UTargetDataUnderMouse::OnTargetDataReplicatedCallback);

		//判断在服务器端，上面的委托是否已经广播过
		const bool bCalledDelegate = AbilitySystemComponent.Get()->CallReplicatedTargetDataDelegatesIfSet(SpecHandle, ActivationPredictionKey);
		if(!bCalledDelegate)
		{
			//设置服务器端等待PlayerData数据的上传
			SetWaitingOnRemotePlayerData();
		}
	}
	
}

void UTargetDataUnderMouse::SendMouseCursorData()
{
	//创建一个预测窗口，该窗口允许客户端在不确定服务器响应的情况下，对游戏状态进行预测性更新。
	FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent.Get(), true);


	APlayerController* PC = Ability->GetCurrentActorInfo()->PlayerController.Get();
	FHitResult CursorHit;
	PC->GetHitResultUnderCursor(ECC_Target, false, CursorHit);

	FGameplayAbilityTargetDataHandle DataHandle;//数据句柄
	FGameplayAbilityTargetData_SingleTargetHit* Data = new FGameplayAbilityTargetData_SingleTargetHit();//单目标命中数据
	Data->HitResult = CursorHit;//设置命中结果
	DataHandle.Add(Data);//添加单目标命中数据

	AbilitySystemComponent->ServerSetReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey(),DataHandle, FGameplayTag(), AbilitySystemComponent->ScopedPredictionKey);

	//判断服务器端是否通过验证
	if(ShouldBroadcastAbilityTaskDelegates())
	{
		ValidData.Broadcast(DataHandle);//广播命中位置
	}

}

void UTargetDataUnderMouse::OnTargetDataReplicatedCallback(const FGameplayAbilityTargetDataHandle& DataHandle, FGameplayTag ActivationTag)
{
	//通知客户端 服务器端已经接收并处理了从客户端复制的目标数据（将服务器的TargetData应用到客户端，并清除掉缓存）
	AbilitySystemComponent->ConsumeClientReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey());
	//判断服务器端是否通过验证
	if(ShouldBroadcastAbilityTaskDelegates())
	{
		ValidData.Broadcast(DataHandle);
	}
}
